/*
 * miniFreeRTOS
 * Copyright (c) 2024- yanl1229@163.com.
 * Written by yanl1229
 *
 * This code is licensed under the GPL.
 */

#include "task.h"
#include "mutex.h"
#include "mm.h"


static void mutex_init(struct mutex * lock)
{
    /* 设置互斥锁计数器值 */
    lock->count = 1;
    lock->owner = NULL;
    lock->waiter_list = NULL;
}

/**
 * mutex_create: 创建互斥锁
*/
struct mutex * mutex_create()
{
    struct mutex *lock = NULL;

    lock = (struct mutex *)kmalloc(sizeof(struct mutex));
    if (lock != NULL)
        mutex_init(lock);
    list_init(&lock->waiter_list);
    return lock;
}

void mutex_delete(struct mutex *lock)
{
    if (lock != NULL)
        kfree(lock);
}

static void mutex_uninherit_priority(struct task_struct *tsk)
{
    if (tsk != NULL)
    {
        tsk->mutex_count--;
        /* 锁的持有发生过优先级继承问题 */
        if (tsk->prio != tsk->static_prio)
        {
            if (tsk->mutex_count == 0)
            {
                tsk->prio = tsk->static_prio;
                enqueue_task(tsk);
            }
        }
    }
}

/**
 *  释放互斥锁
 */
uint32_t mutex_unlock(struct mutex * lock)
{
    for( ; ; )
    {
        disable_interrupt();
        {
            /**
             * 释放互斥锁
             */
            if (lock->count < 1)
            {

                lock->count = lock->count + 1;
                mutex_uninherit_priority(lock->owner);
                /*
                 * 有任务阻塞在等待互斥锁
                 */
                if (list_is_empty(lock->waiter_list) == 0)
                {
                    /* 有高优先级任务存在，直接抢占当前任务 */
                    if (remove_from_event_queue(lock->waiter_list))
                        yield();
                }

                enable_interrupt();

                return 1;
            }
        }
        enable_interrupt();

        return 0;
    }
}

/**
 * @pxMutexHolder: 持有互斥锁的任务
 */
uint32_t mutex_inherit_priority(struct task_struct *tsk)
{
    uint32_t ret = 0;

    if (tsk != NULL)
    {
        /**
         * 出现高优先级任务尝试获取已经被低优先级任务持有的互斥锁
         */
        if (tsk->prio < current->prio)
        {
            /* 低优先级的任务，已经准备要开始运行 */
            if (tsk->in_ready)
            {
                /**
                 * 提高低优先级任务的优先级
                 */
                tsk->prio = current->prio;
                enqueue_task(tsk);
            }
            else
            {
                /**
                 * 只提高低优先级任务的优先级
                 */
                tsk->prio = current->prio;
            }
             /* 出现优先级继承 */
            ret = 1;
        }
        else
        {
            /* 尝试获取互斥锁的任务的优先级大于锁的持有者任务的优先级，也出现优先级继承 */
            if (tsk->static_prio < current->prio)
                ret = 1;
        }
    }

    return ret;
}

/**
 * @pxMutexHolder: 互斥锁的持有者
 * @highest_prio: 等待互斥锁的最高优先级的任务
 */
void mutex_inherit_improve(struct task_struct *tsk, uint32_t highest_prio)
{
    uint32_t prio;

    if (tsk != NULL)
    {
        if (tsk->static_prio < highest_prio)
            prio = highest_prio;
        else
            prio = tsk->static_prio;

        /* Does the priority need to change? */
        if (tsk->prio != prio)
        {
            /**
             * 任务只持有一把互斥锁,这样就可以回复任务原有的优先级
             */
            if (tsk->mutex_count == 1)
            {
                /* 临时调高持有互斥锁任务的优先级 */
                tsk->prio = prio;

                /* 优先级调整后，如果之前任务在就绪队列中，重新入队 */
                if (tsk->in_ready) {
                    dequeue_task(tsk);
                    enqueue_task(tsk);
                }
            }
        }
    }
}

static int mutex_common_lock(struct mutex * lock, int noblock)
{
    uint32_t inheritance_occurred = 0;

    for( ; ; )
    {
        disable_interrupt();
        {
            uint32_t lock_count = lock->count;
            /* 互斥锁空闲 */
            if (lock_count > 0)
            {
                /* 获取互斥锁 */
                lock->count = lock_count - 1;
                lock->owner = current;
                enable_interrupt();
                return 1;
            } else {
                /* 不等待，直接返回 */
                if (noblock == 1)
                {
                    enable_interrupt();
                    return 0;
                }
            }
        }
        enable_interrupt();

        sched_suspend();

        /* 未超时, 并且互斥锁还没被释放 */
        if (lock->count == 0)
        {
            /* 判断是否出现了优先级继承问题 */
            inheritance_occurred = mutex_inherit_priority(lock->owner);
            /* 当前任务被挂到等待队列 */
            dequeue_task(current);
            list_add_tail(lock->waiter_list, &current->event_node);
             /* 任务已经被阻塞，不可抢占情况下，直接让出当前cpu */
            if (sched_resume() == 0)
                yield();
        }
        else
        {
            /* 互斥锁被释放，再次尝试获取 */
            sched_resume();
        }
    }
}
/**
 * 获取互斥锁
 * @wait_ticks:   超时时间
 */
uint32_t mutex_lock(struct mutex * lock)
{
    return mutex_common_lock(lock, 0);
}

uint32_t mutex_try_lock(struct mutex * lock)
{
    return mutex_common_lock(lock, 1);
}